package it.antonio.ilpizze.db.core;

import it.antonio.ilpizze.db.DbException;
import it.antonio.ilpizze.db.Monitor;
import it.antonio.ilpizze.db.statistics.MeasureContext;
import it.antonio.ilpizze.db.statistics.MeasureMetric;
import it.antonio.ilpizze.db.statistics.Statistics;
import it.antonio.ilpizze.db.statistics.StatisticsResult;

import java.util.EnumMap;
import java.util.LinkedList;
import java.util.List;

public class MonitorManager implements Monitor{
	
	private final static long MILLI_SECONDS = 1000000;
	
	private EnumMap<Statistics, List<StatisticRecord>> toRecord = new EnumMap<Statistics, List<StatisticRecord>>(Statistics.class); 
	private EnumMap<Statistics, RecordingProcess> processRecording = new EnumMap<Statistics, RecordingProcess>(Statistics.class); 
	
	private MeasureContext context = new MeasureContext();
	
	public void start(Statistics stat){
		RecordingProcess process = processRecording.get(stat);
		if(process != null){
			processRecording.get(stat).startTime = currentTime();	
		}
		
	}
	
	public void stop(Statistics stat){
		RecordingProcess process = processRecording.get(stat);
		if(process != null){
			process.endTime = currentTime();
			
			StatisticRecord record = new StatisticRecord(process.endTime - process.startTime);
			List<StatisticRecord> records = toRecord.get(stat);
			records.add(record);
		}
		
		
	}
	
	public MeasureContext registerMeasure() {
		return context;
	}
	
	@Override
	public void reset() {
		toRecord.clear();
		processRecording.clear();
	}

	@Override
	public void record(Statistics stat) {
		processRecording.put(stat, new RecordingProcess());
		toRecord.put(stat, new LinkedList<StatisticRecord>());
	}
	@Override
	public void record(Statistics... stats) {
		for(Statistics stat: stats){
			record(stat);
		}
	}
	@Override
	public <T> T measure(MeasureMetric<T> metric) {
		return metric.calculate(context);
	}

	@Override
	public StatisticsResult stats(Statistics stat) {
		List<StatisticRecord> records = toRecord.get(stat);
		if(records == null) throw new DbException("No monitor record: " + stat);
		return new StatisticsResult(records);
	}

	
	private class RecordingProcess {
		private long startTime;
		private long endTime;
	}
	
	private long currentTime(){
		return System.nanoTime() / MILLI_SECONDS;
	}

	
	
}
